## Stopwatch program
## Copyright (c) 2010-2020.
## Santosh G. Vattam
## This code is licensed under GPLv3. This is free software and is free to download,
## run, modify and redistribute provided the author is given credit.
## This code has been written for the lab assignment for the ESE 541 course -
## "Embedded software for Life Critical Systems" at University of Pennsylvania for
## the Fall 2010. 
## The LED Display parts of this program have been based on the LED Clock 
## implementation presented by "bumsfeld" at the 
## Daniweb community <http://www.daniweb.com/code/snippet216962.html>

import wx
import wx.gizmos as gizmos

# Creating a class derived from the standard wxpython class for the Frame window
class MainFrame( wx.Frame ):
    '''MainFrame class derived from the wxPython Frame class.    
    '''
    cs = 0 # The counter for 1/100th of a second (cs == centisecond)
    ss = 0 # The counter for the seconds
    mm = 0 # The counter for the minutes
    def __init__(self):
        wx.Frame.__init__(self, None, size = (500, 200), title = 'Stop Watch')
        (ID_START, ID_STOP, ID_RESET) = (1, 2, 3) # Setting the ids to the id numbers for event handling.
        self.MainPanel = wx.Panel(self) # Initializing the panel
        self.Tools = wx.ToolBar(self, id = -1, style = wx.TB_HORIZONTAL | wx.TB_TEXT) #Initiating toolbar in the frame
        self.Tools.AddLabelTool(ID_START, 'Start', wx.Bitmap('play-button-rsz.jpg')) #Adding Start button
        self.Tools.AddLabelTool(ID_STOP, 'Stop', wx.Bitmap('pause-button-rsz.jpg')) #Adding Stop button
        self.Tools.AddLabelTool(ID_RESET, 'Reset', wx.Bitmap('reset-button-rsz.jpg')) #Adding Reset button
        self.SetToolBar(self.Tools) #Setting the toolbar to the frame
        # wxPython has a gizmos class that contains LED display. 
        self.led = gizmos.LEDNumberCtrl( self, -1, wx.DefaultPosition, (500, 100), gizmos.LED_ALIGN_CENTER ) 
        #Initializing the LED display
        wx.Frame.Bind( self, wx.EVT_TOOL, self.OnStart, id = ID_START ) #binding the start button event to the event handler
        wx.Frame.Bind( self, wx.EVT_TOOL, self.OnStop, id = ID_STOP ) #binding the stop button event to the event handler
        wx.Frame.Bind( self, wx.EVT_TOOL, self.OnReset, id = ID_RESET ) #binding the reset button event to the event handler
        self.Tools.Realize() #Displays the toolbar on the frame

    def OnStart( self, event ): 
        ''' This method sets up the timer class in wx and calls the stopwatch method every 10ms.
        '''
        self.stopwatch(MainFrame)
        self.timer = wx.Timer(self, -1) #Initializing the timer instance
        self.timer.Start(10) #Setting the timer duration
        self.Bind(wx.EVT_TIMER, self.stopwatch) #Binding the timer event to the event handler method
        
    def stopwatch(self, event):
        ''' This method is the core stopwatch method.
        '''
        MainFrame.cs += 1 #Increment the centisecond
        if MainFrame.cs % 100 == 0: #If the no. of centiseconds == 100 increment the seconds counter
            MainFrame.cs = 0
            MainFrame.ss += 1
        if MainFrame.ss % 60 == 0 and MainFrame.ss != 0: #If the no. of seconds is equal to 60 increment the minutes counter
            MainFrame.ss = 0
            MainFrame.mm += 1
        ts = str(MainFrame.mm) + " " + str(MainFrame.ss) + " " + str(MainFrame.cs) 
        #Formatting to a string for displaying on LED
        self.led.SetValue(ts) #Setting up the display

    def OnStop( self, event ):
        ''' If the timer instance is running, stops the timer instance.
        '''
        if (self.timer.IsRunning()): 
            self.timer.Stop()

    def OnReset( self, event ):
        ''' Resets the each of the stopwatch values to 0
        '''
        MainFrame.cs = 0
        MainFrame.ss = 0
        MainFrame.mm = 0
        ts = str(MainFrame.mm) + " " + str(MainFrame.ss) + " " + str(MainFrame.cs) 
        #Formats to a string for displaying on LED
        self.led.SetValue(ts) #Setting up the display

# This code below is to check if this program is being run independently or if it is used by 
# a different module. If the program is run independently the code is executed by itself,
# if not the code is executed as part of a module and will behave in a module specific way.
if __name__ == '__main__':
    sw = wx.App()
    sw_frame = MainFrame()
    sw_frame.Show(True)
    sw.SetTopWindow(sw_frame)
    sw.MainLoop()
